package com.jvmmonitor.service;

import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.jvmmonitor.jmx.JmxMonitor;
import com.jvmmonitor.model.GcStats;
import com.jvmmonitor.model.JvmAdvice;
import com.jvmmonitor.model.MemoryStats;
import com.jvmmonitor.model.ObjectSizeStats;
import com.jvmmonitor.util.ConfigLoader;

/**
 * 内存分析器，负责分析内存增长原因和生成JVM优化建议
 */
public class MemoryAnalyzer {
    private static final Logger logger = LoggerFactory.getLogger(MemoryAnalyzer.class);
    
    // JMX监控服务
    private final JmxMonitor jmxMonitor;
    
    // 对象大小监控服务
    private final ObjectSizeMonitor objectSizeMonitor;
    
    /**
     * 构造方法
     */
    public MemoryAnalyzer() {
        this.jmxMonitor = new JmxMonitor();
        this.objectSizeMonitor = new ObjectSizeMonitor();
    }
    
    /**
     * 分析内存增长原因
     */
    public void analyzeMemoryGrowth() {
        if (!ConfigLoader.isMemoryGrowthAnalysisEnabled()) {
            return;
        }
        
        try {
            logger.info("Starting memory growth analysis...");
            
            // 获取内存统计历史数据
            List<MemoryStats> memoryStatsHistory = jmxMonitor.getMemoryStatsHistory();
            if (memoryStatsHistory.size() < 2) {
                logger.debug("Insufficient memory stats history for analysis");
                return;
            }
            
            // 获取对象大小统计历史数据
            List<ObjectSizeStats> objectSizeStatsHistory = objectSizeMonitor.getObjectSizeStatsHistory();
            
            // 分析堆内存增长
            analyzeHeapMemoryGrowth(memoryStatsHistory);
            
            // 分析非堆内存增长
            analyzeNonHeapMemoryGrowth(memoryStatsHistory);
            
            // 分析对象大小变化
            if (!objectSizeStatsHistory.isEmpty()) {
                analyzeObjectSizeChanges(objectSizeStatsHistory);
            }
            
            logger.info("Memory growth analysis completed");
        } catch (Exception e) {
            logger.error("Failed to analyze memory growth: {}", e.getMessage(), e);
        }
    }
    
    /**
     * 分析堆内存增长
     */
    private void analyzeHeapMemoryGrowth(List<MemoryStats> memoryStatsHistory) {
        // 获取最新和前一个内存统计数据
        MemoryStats latest = memoryStatsHistory.get(memoryStatsHistory.size() - 1);
        MemoryStats previous = memoryStatsHistory.get(memoryStatsHistory.size() - 2);
        
        // 计算堆内存变化
        long heapGrowth = latest.getHeapMemoryUsed() - previous.getHeapMemoryUsed();
        double growthRate = (double) heapGrowth / (latest.getTimestamp() - previous.getTimestamp()) * 1000;
        
        logger.info("Heap Memory Growth Analysis:");
        logger.info("  Current Heap Usage: {} / {} ({}%)", 
                formatBytes(latest.getHeapMemoryUsed()),
                formatBytes(latest.getHeapMemoryMax()),
                (int) ((double) latest.getHeapMemoryUsed() / latest.getHeapMemoryMax() * 100));
        logger.info("  Heap Growth in Last Interval: {} ({} bytes/sec)", 
                formatBytes(heapGrowth),
                (int) growthRate);
        
        // 分析堆内存使用情况
        if (latest.getHeapMemoryUsed() > latest.getHeapMemoryMax() * 0.8) {
            logger.warn("Heap memory usage is high ({:.1f}% of max)", 
                    (double) latest.getHeapMemoryUsed() / latest.getHeapMemoryMax() * 100);
        }
    }
    
    /**
     * 分析非堆内存增长
     */
    private void analyzeNonHeapMemoryGrowth(List<MemoryStats> memoryStatsHistory) {
        // 获取最新和前一个内存统计数据
        MemoryStats latest = memoryStatsHistory.get(memoryStatsHistory.size() - 1);
        MemoryStats previous = memoryStatsHistory.get(memoryStatsHistory.size() - 2);
        
        // 计算非堆内存变化
        long nonHeapGrowth = latest.getNonHeapMemoryUsed() - previous.getNonHeapMemoryUsed();
        double nonHeapRatio = jmxMonitor.getNonHeapMemoryRatio();
        
        logger.info("Non-Heap Memory Growth Analysis:");
        logger.info("  Current Non-Heap Usage: {} / {} ({}%)", 
                formatBytes(latest.getNonHeapMemoryUsed()),
                formatBytes(latest.getNonHeapMemoryMax() > 0 ? latest.getNonHeapMemoryMax() : latest.getNonHeapMemoryCommitted()),
                (int) ((double) latest.getNonHeapMemoryUsed() / latest.getNonHeapMemoryCommitted() * 100));
        logger.info("  Non-Heap Growth in Last Interval: {}", formatBytes(nonHeapGrowth));
        logger.info("  Non-Heap Memory Ratio: {:.1f}% of total memory", nonHeapRatio * 100);
        
        // 分析非堆内存各区域
        logger.info("  Non-Heap Memory Breakdown:");
        logger.info("    Metaspace: {} ({}% of non-heap)", 
                formatBytes(latest.getMetaspaceUsed()),
                (int) (jmxMonitor.getMetaspaceRatio() * 100));
        logger.info("    Direct Memory: {} ({}% of non-heap)", 
                formatBytes(latest.getDirectMemoryUsed()),
                (int) (jmxMonitor.getDirectMemoryRatio() * 100));
        logger.info("    Code Cache: {} ({}% of non-heap)", 
                formatBytes(latest.getCodeCacheUsed()),
                (int) ((double) latest.getCodeCacheUsed() / latest.getNonHeapMemoryUsed() * 100));
    }
    
    /**
     * 分析对象大小变化
     */
    private void analyzeObjectSizeChanges(List<ObjectSizeStats> objectSizeStatsHistory) {
        ObjectSizeStats latest = objectSizeStatsHistory.get(objectSizeStatsHistory.size() - 1);
        
        logger.info("Object Size Change Analysis:");
        logger.info("  Total Objects Created: {}", latest.getTotalObjectCount());
        logger.info("  Total Memory Allocated: {}", formatBytes(latest.getTotalObjectSize()));
        
        // 分析大对象情况
        if (latest.getLargeObjectCount() > 0) {
            logger.info("  Large Objects Created: {} ({}% of total objects)", 
                    latest.getLargeObjectCount(),
                    (int) ((double) latest.getLargeObjectCount() / latest.getTotalObjectCount() * 100));
        }
    }
    
    /**
     * 生成JVM优化建议
     */
    public void generateJvmAdvice() {
        if (!ConfigLoader.isJvmAdviceEnabled()) {
            return;
        }
        
        try {
            logger.info("Generating JVM optimization advice...");
            
            JvmAdvice jvmAdvice = new JvmAdvice();
            
            // 获取最新的内存统计数据
            MemoryStats latestMemoryStats = jmxMonitor.getLatestMemoryStats();
            ObjectSizeStats latestObjectSizeStats = objectSizeMonitor.getLatestObjectSizeStats();
            
            if (latestMemoryStats != null) {
                // 堆内存大小建议
                generateHeapSizeAdvice(jvmAdvice, latestMemoryStats);
                
                // 非堆内存建议
                generateNonHeapAdvice(jvmAdvice, latestMemoryStats);
            }
            
            if (latestObjectSizeStats != null) {
                // 对象大小相关建议
                generateObjectSizeAdvice(jvmAdvice, latestObjectSizeStats);
            }
            
            // GC相关建议
            generateGcAdvice(jvmAdvice);
            
            // 输出建议
            outputJvmAdvice(jvmAdvice);
            
            logger.info("JVM optimization advice generated");
        } catch (Exception e) {
            logger.error("Failed to generate JVM advice: {}", e.getMessage(), e);
        }
    }
    
    /**
     * 生成GC相关建议
     */
    private void generateGcAdvice(JvmAdvice jvmAdvice) {
        // 获取GC统计历史数据
        List<GcStats> gcStatsHistory = jmxMonitor.getGcStatsHistory();
        if (gcStatsHistory.isEmpty()) {
            return;
        }
        
        // 统计不同类型GC的频率
        int youngGcCount = 0;
        int oldGcCount = 0;
        int fullGcCount = 0;
        
        // 删除未使用的变量
        // long totalGcDuration = 0;
        long maxGcDuration = 0;
        long fullGcDuration = 0;
        
        // 统计最近5分钟内的GC情况
        long fiveMinutesAgo = System.currentTimeMillis() - 5 * 60 * 1000;
        
        for (GcStats gcStats : gcStatsHistory) {
            if (gcStats.getStartTime() < fiveMinutesAgo) {
                continue;
            }
            
            // 删除未使用的变量累加
            // totalGcDuration += gcStats.getDuration();
            if (gcStats.getDuration() > maxGcDuration) {
                maxGcDuration = gcStats.getDuration();
            }
            
            switch (gcStats.getGcType()) {
                case YOUNG_GC:
                    youngGcCount++;
                    break;
                case OLD_GC:
                    oldGcCount++;
                    break;
                case FULL_GC:
                    fullGcCount++;
                    fullGcDuration += gcStats.getDuration();
                    break;
                default:
                    break;
            }
        }
        
        // 生成GC频率相关建议
        if (youngGcCount > 100) { // 5分钟内Young GC超过100次
            jvmAdvice.addAdviceItem(new JvmAdvice.AdviceItem(
                    JvmAdvice.AdviceType.GC_ALGORITHM,
                    JvmAdvice.AdviceLevel.WARNING,
                    "High Young GC frequency",
                    "Consider increasing young generation size or optimizing object creation",
                    String.format("Young GC occurred %d times in the last 5 minutes", youngGcCount)
            ));
        }
        
        if (oldGcCount > 5) { // 5分钟内Old GC超过5次
            jvmAdvice.addAdviceItem(new JvmAdvice.AdviceItem(
                    JvmAdvice.AdviceType.GC_ALGORITHM,
                    JvmAdvice.AdviceLevel.WARNING,
                    "High Old GC frequency",
                    "Consider increasing old generation size or reducing long-lived objects",
                    String.format("Old GC occurred %d times in the last 5 minutes", oldGcCount)
            ));
        }
        
        if (fullGcCount > 1) { // 5分钟内Full GC超过1次
            jvmAdvice.addAdviceItem(new JvmAdvice.AdviceItem(
                    JvmAdvice.AdviceType.GC_ALGORITHM,
                    JvmAdvice.AdviceLevel.CRITICAL,
                    "Full GC occurred",
                    "Consider optimizing memory usage or changing GC algorithm",
                    String.format("Full GC occurred %d times in the last 5 minutes, total duration: %d ms", 
                            fullGcCount, fullGcDuration)
            ));
        }
        
        // 生成GC持续时间相关建议
        if (maxGcDuration > 1000) { // 单次GC超过1秒
            jvmAdvice.addAdviceItem(new JvmAdvice.AdviceItem(
                    JvmAdvice.AdviceType.GC_ALGORITHM,
                    JvmAdvice.AdviceLevel.WARNING,
                    "Long GC duration",
                    "Consider using a low-latency GC algorithm like G1GC or ZGC",
                    String.format("Maximum GC duration: %d ms", maxGcDuration)
            ));
        }
    }
    
    /**
     * 生成堆内存大小建议
     */
    private void generateHeapSizeAdvice(JvmAdvice jvmAdvice, MemoryStats memoryStats) {
        double heapUsageRatio = (double) memoryStats.getHeapMemoryUsed() / memoryStats.getHeapMemoryMax();
        
        // 如果堆内存使用率超过90%，建议增加堆大小
        if (heapUsageRatio > 0.9) {
            jvmAdvice.addAdviceItem(new JvmAdvice.AdviceItem(
                    JvmAdvice.AdviceType.HEAP_SIZE,
                    JvmAdvice.AdviceLevel.WARNING,
                    "High heap memory usage",
                    String.format("Consider increasing -Xmx to at least %s", 
                            formatBytes((long) (memoryStats.getHeapMemoryUsed() * 1.5))),
                    String.format("Current heap usage is %.1f%% of max heap size", heapUsageRatio * 100)
            ));
        }
        
        // 如果堆内存使用率低于30%，建议减小堆大小
        else if (heapUsageRatio < 0.3 && memoryStats.getHeapMemoryMax() > 256 * 1024 * 1024) {
            jvmAdvice.addAdviceItem(new JvmAdvice.AdviceItem(
                    JvmAdvice.AdviceType.HEAP_SIZE,
                    JvmAdvice.AdviceLevel.INFO,
                    "Low heap memory usage",
                    String.format("Consider decreasing -Xmx to around %s to save system resources", 
                            formatBytes((long) (memoryStats.getHeapMemoryUsed() * 1.5))),
                    String.format("Current heap usage is %.1f%% of max heap size", heapUsageRatio * 100)
            ));
        }
    }
    
    /**
     * 生成非堆内存建议
     */
    private void generateNonHeapAdvice(JvmAdvice jvmAdvice, MemoryStats memoryStats) {
        // 元空间建议
        double metaspaceUsageRatio = (double) memoryStats.getMetaspaceUsed() / memoryStats.getMetaspaceCommitted();
        if (metaspaceUsageRatio > 0.9) {
            jvmAdvice.addAdviceItem(new JvmAdvice.AdviceItem(
                    JvmAdvice.AdviceType.METASPACE,
                    JvmAdvice.AdviceLevel.WARNING,
                    "High metaspace usage",
                    "Consider increasing Metaspace size with -XX:MaxMetaspaceSize",
                    String.format("Current metaspace usage is %.1f%% of committed size", metaspaceUsageRatio * 100)
            ));
        }
        
        // 直接内存建议
        if (memoryStats.getDirectMemoryUsed() > 100 * 1024 * 1024) { // 超过100MB
            jvmAdvice.addAdviceItem(new JvmAdvice.AdviceItem(
                    JvmAdvice.AdviceType.DIRECT_MEMORY,
                    JvmAdvice.AdviceLevel.INFO,
                    "High direct memory usage",
                    "Consider setting -XX:MaxDirectMemorySize to limit direct memory growth",
                    String.format("Current direct memory usage: %s", formatBytes(memoryStats.getDirectMemoryUsed()))
            ));
        }
    }
    
    /**
     * 生成对象大小相关建议
     */
    private void generateObjectSizeAdvice(JvmAdvice jvmAdvice, ObjectSizeStats objectSizeStats) {
        // 大对象建议
        if (objectSizeStats.getLargeObjectCount() > 100) { // 超过100个大对象
            jvmAdvice.addAdviceItem(new JvmAdvice.AdviceItem(
                    JvmAdvice.AdviceType.LARGE_OBJECT,
                    JvmAdvice.AdviceLevel.INFO,
                    "Many large objects created",
                    "Consider reviewing code for large object creation patterns and use appropriate data structures",
                    String.format("Created %d large objects in the last interval", objectSizeStats.getLargeObjectCount())
            ));
            
            // 建议使用G1GC处理大对象
            jvmAdvice.addAdviceItem(new JvmAdvice.AdviceItem(
                    JvmAdvice.AdviceType.GC_ALGORITHM,
                    JvmAdvice.AdviceLevel.INFO,
                    "Large object handling",
                    "Consider using G1GC (-XX:+UseG1GC) for better large object management",
                    "Current GC algorithm may not be optimal for large object handling"
            ));
        }
    }
    
    /**
     * 输出JVM建议
     */
    private void outputJvmAdvice(JvmAdvice jvmAdvice) {
        if (jvmAdvice.getAdviceItems().isEmpty()) {
            logger.info("No JVM optimization advice generated");
            return;
        }
        
        logger.info("JVM Optimization Advice:");
        for (JvmAdvice.AdviceItem adviceItem : jvmAdvice.getAdviceItems()) {
            logger.info("  [{}] {}", adviceItem.getLevel(), adviceItem.getDescription());
            logger.info("    Suggestion: {}", adviceItem.getSuggestion());
            logger.info("    Reason: {}", adviceItem.getReason());
        }
    }
    
    /**
     * 格式化字节数为可读格式
     * @param bytes 字节数
     * @return 格式化后的字符串
     */
    private String formatBytes(long bytes) {
        if (bytes < 1024) {
            return bytes + "B";
        } else if (bytes < 1024 * 1024) {
            return String.format("%.1fKB", bytes / 1024.0);
        } else if (bytes < 1024 * 1024 * 1024) {
            return String.format("%.1fMB", bytes / (1024.0 * 1024.0));
        } else {
            return String.format("%.1fGB", bytes / (1024.0 * 1024.0 * 1024.0));
        }
    }
}